package com.neusoft.boss.service.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.neusoft.boss.common.client.RedisClient;
import com.neusoft.boss.common.consanst.KeyConst;
import com.neusoft.boss.common.returndata.OperatorReturn;
import com.neusoft.boss.db.domain.PmsMenu;
import com.neusoft.boss.db.mapper.PmsMenuMapper;
import com.neusoft.boss.model.menus.entity.MenuItem;
import com.neusoft.boss.model.menus.entity.SubMenu;
import com.neusoft.boss.utils.JwtUtil;
import com.neusoft.boss.db.domain.PmsOperator;
import com.neusoft.boss.db.mapper.PmsOperatorMapper;
import com.neusoft.boss.common.query.LoginQuery;
import com.neusoft.boss.service.LoginService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 *
 */
@Service
public class LoginServiceImpl implements LoginService {

    @Resource
    private RedisClient redisClient;
    @Resource
    private PmsOperatorMapper pmsOperatorMapper;
    @Resource
    PmsMenuMapper pmsMenuMapper;

    @Override
    public OperatorReturn select(LoginQuery loginQuery) {
        //1：使用plus.eq方法查询条件查询
        QueryWrapper<PmsOperator> query = new QueryWrapper<>();
        query.eq("login_name", loginQuery.getLoginName());
        PmsOperator pms = pmsOperatorMapper.selectOne(query);//sql语句
        if (pms == null) {
            //登陆失败提示登录失败信息
        }

        //成功获取密码 ，密码的值加盐值
        //1：获取salt
        String salt = pms.getSalt();
        String pwd = DigestUtil.md5Hex(loginQuery.getLoginPwd() + salt);//前端的密码盐值加上后端的salt值就是密码
        if (!pwd.equals(pms.getLoginPwd())) {
            //登陆失败密码不对
        }
        //登陆成功
        //封装进入jwt中
        String jwt = JwtUtil.createJWT(String.valueOf(pms.getId()), 120);
        //装入redis中
        //key是自定义的常量

        Map<String, String> data = new HashMap<>();
        data.put("operatorId", String.valueOf(pms.getId()));//将用户id转为字符串存入map集合中
        data.put("jwt", jwt);//将jwt装入map集合中
        data.put("logintime", new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()));//时间戳
        redisClient.setHash(KeyConst.OPERATOR_LOGIN_JWT, data, 120, TimeUnit.MINUTES);

        return new OperatorReturn(pms.getId(), pms.getShowName(), jwt);
    }

    /**
     * redis缓存存储数据
     * 1:从redis中取出数据
     * 2：有：直接使用
     * 3：如果redis中没有
     *
     * @param operatorId
     * @return
     */

    @Override
    public List<SubMenu> getMenus(Long operatorId) {
        //json中有数据就把数据转换为list
        List<SubMenu> SubMenuList = new ArrayList<>();
        try {//如果出现错误异常
            //存到redis中
            String MENUkEY = KeyConst.OPERATOR_MENUS + operatorId;
             String menuJson = redisClient.getVal(MENUkEY);
            if (StrUtil.isNotBlank(menuJson)) {
                SubMenuList = JSONUtil.toList(menuJson, SubMenu.class);//将JSON数组转换为list 类是SubMenu
            } else {
                synchronized (this) {//从库中取出来存时是一块执行的
                    //避免另外一个进程重复查询数据库
                    menuJson = redisClient.getVal(MENUkEY);
                    if (StrUtil.isNotBlank(menuJson)) {
                        SubMenuList = JSONUtil.toList(menuJson, SubMenu.class);//将JSON数组转换为list 类是SubMenu
                    } else {
                        //没有数据的话将数据库中的数据赋给list
                        SubMenuList = getSubMenus(operatorId);
                        //然后存入redis中
                        if (SubMenuList.size() > 0) {
                            redisClient.setVal(MENUkEY, JSONUtil.toJsonStr(SubMenuList));
                        }
                    }
                }
            }
        } catch (Exception e) {//实在有问题再次查询
            e.printStackTrace();
            SubMenuList = getSubMenus(operatorId);
            //补偿机制，前面出现异常的话这个机制直接从数据库中取
        }


        return SubMenuList;
    }


    //从数据库中查询数据
    private List<SubMenu> getSubMenus(Long operatorId) {
        String numberKey = "";
        List<PmsMenu> MenuList = pmsMenuMapper.selectMenusById(operatorId);

        //遍历菜单
        //准备map集合存储数据
        Map<String, List<PmsMenu>> mapMenu = new HashMap<>();
        for (PmsMenu Menu : MenuList) {
            numberKey = Menu.getNumber().substring(0, 4);//取出头四位
            if (mapMenu.containsKey(numberKey)) {
                mapMenu.get(numberKey).add(Menu);
            } else {
                //前四位没有的话存入map中
                List<PmsMenu> list = new ArrayList<>();
                list.add(Menu);


                mapMenu.put(numberKey, list);
            }
        }
        //组装submwnu
        List<SubMenu> subMenuList = new ArrayList<>();
        mapMenu.forEach((number, pmsMenuList) -> {
            SubMenu subMenu = new SubMenu();
            List<MenuItem> itemList = new ArrayList<>();
            pmsMenuList.forEach(pmsMenu -> {
                if ("NO".equals(pmsMenu.getIsLeaf())) {
                    subMenu.setId(pmsMenu.getId());
                    subMenu.setLeaf(pmsMenu.getIsLeaf());
                    subMenu.setName(pmsMenu.getName());
                    subMenu.setUrl(pmsMenu.getUrl());
                    subMenu.setNumber(pmsMenu.getNumber());
                } else {//Menuitem
                    MenuItem item = new MenuItem();
                    item.setId(pmsMenu.getId());
                    item.setLeaf(pmsMenu.getIsLeaf());
                    item.setName(pmsMenu.getName());
                    item.setUrl(pmsMenu.getUrl());
                    item.setNumber(pmsMenu.getNumber());
                    itemList.add(item);
                }
            });
            subMenu.setItems(itemList);
            subMenuList.add(subMenu);
        });
        return subMenuList.stream().sorted(Comparator.comparing(SubMenu::getNumber)).toList();
    }

}
